
use super::AttributeInfo;

// BootstrapMethods属 性 记 录 了 invokedynamic指 令 引 用 的 引 导 方 法 说 明 符

// 如果ClassFile结 构 的 constant_pool表 至 少 有 一 个 CONSTANT_InvokeDynamic_info条 目 
// (§4.4.10)， 那 么 在 ClassFile结 构 的 属 性 表 中 必 须 有 一 个 BootstrapMethods属 性 。
// 在ClassFile结 构 的 属 性 表 中 最 多 只 能 有 一 个 BootstrapMethods属 性 。


// BotstrapMethods_attribute {
// u2 attribute_name_index; // 属性名称索引
// u4 attribute_length; 
// u2 num_bootstrap_methods; // 给出了bootstrap_methods[]数组中的引导方法限定符的数量。
// {   u2 bootstrap_method_ref; // bootstrap_method_ref项的值必须是一个对常量池的有效索引。常量池在该索引处的值必须是一个CONSTANT_MethodHandle_info结构。
//     u2 num_bootstrap_arguments; // bootstrap_argu-ments[]数组成员的数量。
//     u2 bootstrap_arguments[num_bootstrap_arguments]; // 数组的每个成员必须是一个对常量池的有效索引。
// } bootstrap_methods[num_bootstrap_methods]; // 每个成员包含了一个指向常量池CONSTANT_MethodHandle结构的索引值，它代表了一个引导方法。还包含了这个引导方法静态参数的序列（可能为空）。
// }

#[allow(warnings)]
#[derive(Default, Clone)]
pub struct BootstrapMethodsAttribute {
    bootstrap_methods: Vec<BootstrapMethod>,
}

impl AttributeInfo for BootstrapMethodsAttribute {
    fn read_info(&mut self, reader: &mut crate::classfile::ClassReader) {
        self.bootstrap_methods = BootstrapMethod::read(reader);
    }
}

impl BootstrapMethodsAttribute {
    pub fn new() -> BootstrapMethodsAttribute {
        BootstrapMethodsAttribute { bootstrap_methods: vec![] }
    }

    pub fn get_bootstrap_method(&self, index: usize) -> BootstrapMethod {
        self.bootstrap_methods[index].clone()
    }
}

// bootstrap_method_ref：指向CONSTANT_MethodHandle_info
// bootstrap_arguments：必须是下列结构之一
//  CONSTANT_String_info、CONSTANT_Class_info、CONSTANT_Integer_info、CONSTANT_Long_info、
//  CONSTANT_Float_info、CONSTANT_Double_info、CONSTANT_MethodHandle_info或CONSTANT_MethodType_info。
#[allow(warnings)]
#[derive(Default, Clone)]
pub struct BootstrapMethod {
    pub bootstrap_method_ref: u16,
    pub bootstrap_arguments: Vec<u16>,
}

impl BootstrapMethod {
    fn read(reader: &mut crate::classfile::ClassReader) -> Vec<BootstrapMethod> {
        let num_bootstrap_methods = reader.read_u16();
        (0..num_bootstrap_methods).map(|_| {
            BootstrapMethod { 
                bootstrap_method_ref: reader.read_u16(), 
                bootstrap_arguments: reader.read_u16s() 
            }
        }).collect()
    }
}
